package request_models

import (
	"encoding/json"
	"fmt"
	"group-buy/group_buy/internal/common"
	"strconv"

	"github.com/go-resty/resty/v2"
)

type LsMiniAppPay struct {
	MchNo        string           `json:"mch_no"`
	AppId        string           `json:"app_id"`
	MchOrderNo   string           `json:"mch_order_no"`
	WayCode      string           `json:"way_code"`
	Amount       int64            `json:"amount"`
	Currency     string           `json:"currency"`
	Subject      string           `json:"subject"`
	Body         string           `json:"body"`
	NotifyUrl    string           `json:"notify_url"`
	DivisionMode int64            `json:"division_mode"`
	ChannelExtra *MiniAppPayExtra `json:"channel_extra"`
	ReqTime      int64            `json:"req_time"`
	Version      string           `json:"version"`
	Sign         string           `json:"sign"`
	SignType     string           `json:"sign_type"`
}

func (l *LsMiniAppPay) MarshJSON() map[string]string {
	toSerialize := map[string]string{}
	if len(l.MchNo) > 0 {
		toSerialize["mch_no"] = l.MchNo
	}
	if len(l.AppId) > 0 {
		toSerialize["app_id"] = l.AppId
	}
	if len(l.MchOrderNo) > 0 {
		toSerialize["mch_order_no"] = l.MchOrderNo
	}
	if len(l.WayCode) > 0 {
		toSerialize["way_code"] = l.WayCode
	}
	if l.Amount > 0 {
		toSerialize["amount"] = strconv.FormatInt(l.Amount, 10)
	}
	if len(l.Currency) > 0 {
		toSerialize["currency"] = l.Currency
	}
	if len(l.Subject) > 0 {
		toSerialize["subject"] = l.Subject
	}
	if len(l.Body) > 0 {
		toSerialize["body"] = l.Body
	}
	if len(l.NotifyUrl) > 0 {
		toSerialize["notify_url"] = l.NotifyUrl
	}
	if l.ChannelExtra != nil {
		//extraMap := l.ChannelExtra.MarshJSON()
		extraStr, _ := json.Marshal(l.ChannelExtra)
		// sortMap := common.SortMaps(extraMap)
		toSerialize["channel_extra"] = string(extraStr)
	}
	if l.ReqTime > 0 {
		toSerialize["req_time"] = strconv.FormatInt(l.ReqTime, 10)
	}
	if l.DivisionMode > 0 {
		toSerialize["division_mode"] = strconv.FormatInt(l.DivisionMode, 10)
	}
	if len(l.SignType) > 0 {
		toSerialize["sign_type"] = l.SignType
	}
	if len(l.Version) > 0 {
		toSerialize["version"] = l.Version
	}
	if len(l.Sign) > 0 {
		toSerialize["sign"] = l.Sign
	}
	return toSerialize
}

type MiniAppPayExtra struct {
	OpenId   string     `json:"open_id"`
	SubAppid string     `json:"sub_appid"`
	DivList  []*DivInfo `json:"div_list"`
}

func (l *MiniAppPayExtra) MarshJSON() map[string]string {
	toSerialize := map[string]string{}
	if len(l.OpenId) > 0 {
		toSerialize["openid"] = l.OpenId
	}
	if len(l.SubAppid) > 0 {
		toSerialize["sub_appid"] = l.SubAppid
	}
	if len(l.DivList) > 0 {
		divList, _ := json.Marshal(l.DivList)
		toSerialize["div_list"] = string(divList)
	}

	return toSerialize
}

type LsPayRsp struct {
	Status int64  `json:"status"`
	Msg    string `json:"msg"`
	Data   PayRsp `json:"data"`
}
type PayRsp struct {
	MchOrderNo string    `json:"mch_order_no"`
	PayOrderId string    `json:"pay_order_id"`
	Amount     int64     `json:"amount"`
	OrderState int64     `json:"order_state"`
	PayInfo    WxPayInfo `json:"pay_info"`
}
type WxPayInfo struct {
	// TimeStamp string `json:"timeStamp"`
	// Package   string `json:"package"`
	// PaySign   string `json:"paySign"`
	// AppId     string `json:"appId"`
	// SignType  string `json:"signType"`
	// NonceStr  string `json:"nonceStr"`
	AppId      string `json:"app_id"`
	Path       string `json:"path"`
	SchemeCode string `json:"scheme_code"`
}

func (l *LsMiniAppPay) Pay(payKey string) (*LsPayRsp, error) {
	marshJSON := l.MarshJSON()

	sign := common.Sign(marshJSON, payKey)
	l.Sign = sign

	rsp := &LsPayRsp{}
	// marshal, _ := json.Marshal(l.MarshJSON())
	fmt.Printf("pay_req:%s\n", l.MarshJSON())
	client := resty.New()
	resp, err := client.R().SetBody(l.MarshJSON()).SetResult(rsp).Post("https://api.lspay.tech/gateway/unifiedorder")
	if err != nil {
		fmt.Printf("eerrerrrr:%s\n", err)
		return nil, err
	}
	fmt.Printf("pay_resp:%s\n", resp)
	fmt.Printf("pay_rsp:%v\n", rsp)
	return rsp, nil
}

type LsDivision struct {
	MchNo        string         `json:"mch_no"`
	AppId        string         `json:"app_id"`
	MchOrderNo   string         `json:"mch_order_no"`
	WayCode      string         `json:"way_code"`
	Amount       int64          `json:"amount"`
	Currency     string         `json:"currency"`
	Subject      string         `json:"subject"`
	Body         string         `json:"body"`
	NotifyUrl    string         `json:"notify_url"`
	ChannelExtra *DivisionExtra `json:"channel_extra"`
	DivisionMode int64          `json:"division_mode"`
	ReqTime      int64          `json:"req_time"`
	Version      string         `json:"version"`
	Sign         string         `json:"sign"`
	SignType     string         `json:"sign_type"`
}

type DivInfo struct {
	DivAmt  int64  `json:"div_amt"`
	TransIn string `json:"trans_in"`
}

func (l *DivInfo) MarshJSON() map[string]string {
	toSerialize := map[string]string{}
	if len(l.TransIn) > 0 {
		toSerialize["trans_in"] = l.TransIn
	}
	toSerialize["DivAmt"] = strconv.FormatInt(l.DivAmt, 10)
	return toSerialize
}

type DivisionExtra struct {
	ChannelUser string     `json:"channel_user"`
	DivInfos    []*DivInfo `json:"div_infos"`
}

func (l *DivisionExtra) MarshJSON() map[string]string {
	toSerialize := map[string]string{}
	if len(l.ChannelUser) > 0 {
		toSerialize["channel_user"] = l.ChannelUser
	}
	if len(l.DivInfos) > 0 {
		str := ""
		for _, info := range l.DivInfos {
			extraMap := info.MarshJSON()
			sortMap := common.SortMaps(extraMap)
			str += sortMap
		}
		toSerialize["div_infos"] = str
	}
	return toSerialize
}

func (l *LsDivision) MarshJSON() map[string]string {
	toSerialize := map[string]string{}
	if len(l.MchNo) > 0 {
		toSerialize["mch_no"] = l.MchNo
	}
	if len(l.AppId) > 0 {
		toSerialize["app_id"] = l.AppId
	}
	if len(l.MchOrderNo) > 0 {
		toSerialize["mch_order_no"] = l.MchOrderNo
	}
	if len(l.WayCode) > 0 {
		toSerialize["way_code"] = l.WayCode
	}
	if l.Amount > 0 {
		toSerialize["amount"] = strconv.FormatInt(l.Amount, 10)
	}
	if len(l.Currency) > 0 {
		toSerialize["currency"] = l.Currency
	}
	if len(l.Subject) > 0 {
		toSerialize["subject"] = l.Subject
	}
	if len(l.Body) > 0 {
		toSerialize["body"] = l.Body
	}
	if len(l.NotifyUrl) > 0 {
		toSerialize["notify_url"] = l.NotifyUrl
	}
	if l.ChannelExtra != nil {
		extraMap := l.ChannelExtra.MarshJSON()
		sortMap := common.SortMaps(extraMap)
		toSerialize["channel_extra"] = sortMap
	}
	if l.ReqTime > 0 {
		toSerialize["req_time"] = strconv.FormatInt(l.ReqTime, 10)
	}
	if len(l.SignType) > 0 {
		toSerialize["sign_type"] = l.SignType
	}
	if len(l.Version) > 0 {
		toSerialize["version"] = l.Version
	}
	toSerialize["division_mode"] = strconv.FormatInt(l.DivisionMode, 10)
	return toSerialize
}

func (l *LsDivision) Division(payKey string) (*LsDivisionRsp, error) {
	marshJSON := l.MarshJSON()

	sign := common.Sign(marshJSON, payKey)
	l.Sign = sign

	client := resty.New()
	rsp := &LsDivisionRsp{}
	_, err := client.R().SetResult(rsp).SetBody(l).Post("https://api.lspay.tech/gateway/unifiedorder")
	if err != nil {
		return nil, err
	}
	return rsp, nil
}

type LsDivisionRsp struct {
	Status int64       `json:"status"`
	Msg    string      `json:"msg"`
	Data   DivisionRsp `json:"data"`
}

type DivisionRsp struct {
	PayOrderId  string `json:"pay_orderId"`
	TransStatus string `json:"trans_status"`
	MuchOrderNo string `json:"much_order_no"`
	OrderState  int64  `json:"order_state"`
	ErrCode     string `json:"err_code,omitempty"`
	ErrMsg      string `json:"err_msg,omitempty"`
}
